/**
 * Authors: Rafal Witowski, Adam Sznajder
 * Date: 30.06.2011
 * Description: USB microphone device driver.
 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/atomic.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>

MODULE_AUTHOR("Rafal Witowski, Adam Sznajder");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Simple, compatibile with ALSA, USB microphone driver.");

#define CARD_NAME		"usbmic"

#define USBMIC_VENDOR_ID	0xA5A5
#define USBMIC_PRODUCT_ID	0x0001

#define USBMIC_COMMAND_HELLO	0x00
#define USBMIC_COMMAND_PARAM	0x01
#define USBMIC_COMMAND_START	0x02
#define USBMIC_COMMAND_STOP	0x03
#define USBMIC_COMMAND_NONE	0xFF

#define ADC_CLOCK_FREQ		12000000
#define ADC_CLOCK_FREQ_SHDIV	0x00
#define TIMER_MAX		(1 << 16)

#define USBMIC_NUM_URBS		4
#define URB_BUF_SIZE		32

/* standard alsa parameters */
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;

/* parameters from command line */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");


/* mutex */
static DEFINE_MUTEX(probe_mutex);

/* other params */
int adc_chn=1;
module_param(adc_chn,int,0);
MODULE_PARM_DESC(adc_chn, "Number of ADC channel used by microphone");

int dbg_div=1;
module_param(dbg_div,int,0);
MODULE_PARM_DESC(dbg_div, "Driver's internal frequency divider");

/* wait queue for not handled tasks */
DECLARE_WAIT_QUEUE_HEAD (waitqueue);

/* main structure of the device */
struct usbmic_device {
	struct usb_device		*usbdev; /* pointer to usb device */
	struct usb_interface		*usbintf; /* pointer to usb interface */
	struct usb_anchor		usb_anchor; /* pointer to urbs' anchor */
	struct urb			*urbs[USBMIC_NUM_URBS]; /* urbs */
	__u8				usb_ep_in; /* input interface endpoint */
	__u8				usb_ep_out; /* output interface endpoint */	
	int				urb_begin; /* index of urbs' */
	atomic_t			urb_count; /* amount of probes to analyze */
		
	__u8				waiting; /* flag whether the other task is waiting */

	spinlock_t			lock; /* spin lock used to synchronize critical code */
	struct tasklet_struct		tasklet; /* tasklet which will be invoked after interrupt handling */			
	
	struct snd_card			*sndcard; /* pointer to the ALSA sound card */
	struct snd_pcm			*sndpcm; /* pointer to the ALSA pulse count modulation */
	struct snd_pcm_substream	*substream; /* pointer to the ALSA substream */
		
	int				sndcard_idx;
	atomic_t			buffer_pos; /* current buffer's position */
	int				period_pos;	
	int				rate;	
	atomic_t			running; /* flag which indicates whether the pcm is in the CAPTURE mode */	


};

static unsigned int devices_used;

static inline struct device *getdev(struct usbmic_device *device)
{
	return &device->usbintf->dev;
}

/* handles the interrupt after the urb's receipt */
static void usbmic_urbrecv_complete(struct urb *urb);
/* handles the interrupt after the urb's forwarding */ 
static void usbmic_urbsend_complete(struct urb *urb);

/* hardware pcm configuration */
static struct snd_pcm_hardware usbmic_pcm_hardware = {
	.info = SNDRV_PCM_INFO_MMAP |
		SNDRV_PCM_INFO_MMAP_VALID |
		SNDRV_PCM_INFO_BATCH |
		SNDRV_PCM_INFO_BLOCK_TRANSFER |
		SNDRV_PCM_INFO_NONINTERLEAVED,
	.formats = SNDRV_PCM_FMTBIT_U16_BE,
	.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
	.rate_min = 4000,
	.rate_max = 192000,
	.channels_min = 1,
	.channels_max = 1,
	.buffer_bytes_max = 1024 * 1024,
	.period_bytes_min = 64 * 4,
	.period_bytes_max = 512 * 1024,
	.periods_min = 1,
	.periods_max = 2048,
};


/**
 * Method used to submit prepared urbs, can sleep
 */
static int usbmic_submit_urbs(struct usbmic_device *device)
{
	int i;
	int err;
	unsigned int flags;
	
	might_sleep();
	
	/*usb_unpoison_anchored_urbs(&device->usb_anchor);*/
	
	/* for every urb */
	for (i = 0; i < ARRAY_SIZE(device->urbs); ++i) {	
		/*usb_unpoison_urb(device->urbs[i]);*/
		/* submit the urb */
		err = usb_submit_urb(device->urbs[i], GFP_KERNEL);
		if (err < 0) {
			dev_info(getdev(device), "Submit urb: error %d", err);
			/*usb_poison_anchored_urbs(&device->usb_anchor);*/
			
			usb_kill_anchored_urbs(&device->usb_anchor);
			
			return err;			
		}
		/* connect the urb with the anchor */
		usb_anchor_urb(device->urbs[i], &device->usb_anchor);										
	}
	
	return 0;
}

/**
 * Function used to asynchronusly send data.
 */
static int usbmic_send_async(struct usbmic_device *device, void *data, int len)
{
	int err;
	void *buffer	= NULL;	
	struct urb *urb = NULL;
	
	/* initialize the buffer */	
	buffer = kmalloc(len, GFP_ATOMIC);
	if (!buffer) {
		err = -ENOMEM;
		goto error;
	}
	
	/* allocate the memory for urbs */
	urb = usb_alloc_urb(0, GFP_ATOMIC);	
	if (!urb) {
		err = -ENOMEM;
		goto error;
	}
	
	memcpy(buffer, data, len);	
	
	/* fill urbs with data */			
	usb_fill_bulk_urb(urb, device->usbdev, 
			  usb_sndbulkpipe(device->usbdev, device->usb_ep_out),
			  buffer, len, usbmic_urbsend_complete, device);
	urb->transfer_flags |= URB_FREE_BUFFER;
			  
	/* submit the urb */
	err = usb_submit_urb(urb, GFP_ATOMIC);
	if (err < 0)
		goto error;
	
	return 0;
	
error:	
	dev_info(getdev(device), "Send urb: error %d", err);
	usb_free_urb(urb);
	
	return err;
}

/**
 * Function used to send data to the device.
 */
static int usbmic_send(struct usbmic_device *device, void *data, int len,
			int wait)
{
	int err;
	
	/* synchronize */	
	spin_lock(&waitqueue.lock);
	
	device->waiting = 0;	
	/* send asynchronusly data */
	err = usbmic_send_async(device, data, len);			
	if (err < 0) {
		spin_unlock(&waitqueue.lock);
		return err;
	}
	/* if some task is waiting */	
	if (wait) {
		err = wait_event_interruptible_locked(waitqueue, device->waiting);
		if (err < 0)
			dev_info(getdev(device), "Wait: interrupted");
	}
	
	/* unlock the critical section */
	spin_unlock(&waitqueue.lock);
	return 0;
}

/**
 * Function used to handle USBMIC_COMMAND_HELLO command.
 */
static int usbmic_hello(struct usbmic_device *device, int wait)
{
	__u8 command = USBMIC_COMMAND_HELLO;
	return usbmic_send(device, &command, 2, wait);
}

/**
 * Function used to set the frequency.
 */
static int usbmic_set_freq(struct usbmic_device *device, __u16 freq, int wait)
{
	__u8 params[12] = { 0 };
	__u16 cmp_val = (ADC_CLOCK_FREQ >> ADC_CLOCK_FREQ_SHDIV)/freq;
	__u16 cmp_le = cpu_to_le16(cmp_val);
	
	dev_info(getdev(device), "Freq %dHz: cmp 0x%04X (%d) div %d",
		 freq, cmp_le, cmp_le, ADC_CLOCK_FREQ_SHDIV);
		
	params[0] = USBMIC_COMMAND_PARAM;
	memcpy(&params[1], &cmp_le, 2);
	params[3] = ADC_CLOCK_FREQ_SHDIV;
	params[4] = adc_chn;			
	params[5] = 0x10;
	
	return usbmic_send(device, params, sizeof(params), wait);
}

/*
 * Function used to signal that the data transfer has begun.
 */
static int usbmic_data_start(struct usbmic_device *device, int wait)
{
	__u8 command = USBMIC_COMMAND_START;
	return usbmic_send(device, &command, 2, wait);
}

/*
 * Function used to signal that the data transfer is finished.
 */
static int usbmic_data_stop(struct usbmic_device *device, int wait)
{
	__u8 command = USBMIC_COMMAND_STOP;
	return usbmic_send(device, &command, 2, wait);
}

/*
 * Function used to handle data transfer.
 */
static int handle_data(struct usbmic_device *device, struct urb *urb)
{
	struct snd_pcm_runtime *runtime = device->substream->runtime;

	bool period_elapsed = 0;
	u8 *dest;
	int tmp;
	int runtime_buffer_bytes;
	int runtime_period_bytes;
	
	runtime_buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size);
	runtime_period_bytes = frames_to_bytes(runtime, runtime->period_size);
	dest = runtime->dma_area + atomic_read(&device->buffer_pos);			
		
	if (atomic_read(&device->buffer_pos) + 2 <= runtime_buffer_bytes) {
		memcpy(dest, urb->transfer_buffer + 2, 2);
	} else {
		tmp = runtime_buffer_bytes - atomic_read(&device->buffer_pos);
		memcpy(dest, urb->transfer_buffer + 2, tmp);
		memcpy(runtime->dma_area, urb->transfer_buffer + tmp + 2,
			2 - tmp);
	}
	
	atomic_add(2, &device->buffer_pos);
	device->period_pos += 2;
		
	if (atomic_read(&device->buffer_pos) >= runtime_buffer_bytes)
		atomic_sub(runtime_buffer_bytes, &device->buffer_pos);
	if (device->period_pos >= runtime_period_bytes) {
		device->period_pos -= runtime_period_bytes;
		period_elapsed = 1;
	}
	
	return period_elapsed;
}

/*
 * Function used to handle other things than data. 
 */
static void handle_other(struct usbmic_device *device, struct urb *urb)
{
	if (urb->actual_length > 0) {
		*(((char *)(urb->transfer_buffer))+urb->actual_length) = 0x00;
		dev_info(getdev(device), "buf: %s", (char*)urb->transfer_buffer);
	}
}

/*
 * Tasklet invoked after handling the interrupt requested when the all urbs
 * where successfully received.
 */
static void usbmic_urbrecv_complete_bh(unsigned long data)
{
	struct usbmic_device *device = (struct usbmic_device *)data;	
	struct urb *urb;
	bool period_elapsed = 0;
	int err;
	unsigned long flags;
	
	/* while there are some urbs to handle */	
	while (atomic_read(&device->urb_count)) {
		urb = device->urbs[device->urb_begin];

		/* if the device is still in the CAPTURE mode */
		if (atomic_read(&device->running)) {
			/* if urb contains data */
			if (*(char *)(urb->transfer_buffer) == 'D')
				period_elapsed = handle_data(device, urb);
			else
				handle_other(device, urb);
			
			if (period_elapsed)
				snd_pcm_period_elapsed(device->substream);
			
			/* connect the urb with the anchor */		
			usb_anchor_urb(urb, &device->usb_anchor);
			err = usb_submit_urb(urb, GFP_ATOMIC);
			if (err < 0) {
				printk(KERN_INFO "Resubmit urb: error %d", err);
				usb_unanchor_urb(urb);
			}							
		}

		spin_lock(&waitqueue.lock);
		device->waiting = 1;
		wake_up_locked(&waitqueue);
		spin_unlock(&waitqueue.lock);

		atomic_dec(&device->urb_count);						
		++device->urb_begin;
		device->urb_begin %= USBMIC_NUM_URBS;
	}
			
}

/*
 * Function invoked to handle the interrupt requested when data were received.
 */
static void usbmic_urbrecv_complete(struct urb *urb)
{
	struct usbmic_device *device = urb->context;
	
	dev_info(getdev(device), "RECV urb %p stat: %d, len: %u", 
		 urb, urb->status, urb->actual_length);
	
	if (urb->status == -ENOENT ||		/* unlinked */
	    urb->status == -ENODEV ||		/* device removed */
	    urb->status == -ECONNRESET ||	/* unlinked */
	    urb->status == -ESHUTDOWN)		/* device disabled */
		goto xrun;

	if (urb->status >= 0) {
		atomic_inc(&device->urb_count);
		tasklet_schedule(&device->tasklet);
	} else {
		spin_lock(&waitqueue.lock);	
		device->waiting = 1;
		wake_up_locked(&waitqueue);	
		spin_unlock(&waitqueue.lock);		
	}
	
	return;

xrun:
	if(atomic_read(&device->running))
		snd_pcm_stop(device->substream, SNDRV_PCM_STATE_XRUN);				
}


/*
 * Function used to handle the interrupt when the urb has to be sent 
 */
static void usbmic_urbsend_complete(struct urb *urb)
{
	struct usbmic_device *device = urb->context;
	
	dev_info(getdev(device), "SENT urb stat: %d, len: %u", 
		 urb->status, urb->actual_length);
	
	/* if failed we have to unlock waiting */
	if (urb->status < 0) {
		spin_lock(&waitqueue.lock);	
		device->waiting = 1;
		wake_up_locked(&waitqueue);	
		spin_unlock(&waitqueue.lock);
	}	
	
	/* zwalniamy - urb wysylane sa jednokrotnego uzytku */
	usb_free_urb(urb);
}

/*
 * Function used to free all urbs.
 */
static void usbmic_free_urbs(struct usbmic_device *device)
{
	int i;
	
	for (i = 0; i < ARRAY_SIZE(device->urbs); ++i)
		usb_free_urb(device->urbs[i]);
}

/*
 * Function which is used to initialize pcm capture.
 */
static int usbmic_pcmcap_open(struct snd_pcm_substream *substream)
{
	struct usbmic_device *device = substream->private_data;
	
	dev_info(getdev(device), "%s", __FUNCTION__);
		
	substream->runtime->hw = usbmic_pcm_hardware;
	device->substream = substream;

	atomic_set(&device->urb_count, 0);
	
	return 0;
}

/*
 * Function is invoked to close the pcm.
 */
static int usbmic_pcmcap_close(struct snd_pcm_substream *substream)
{
	struct usbmic_device *device = substream->private_data;
	
	dev_info(getdev(device), "%s", __FUNCTION__);
		
	usb_wait_anchor_empty_timeout(&device->usb_anchor, -1);
	/*usb_kill_anchored_urbs(&device->usb_anchor);*/	
	
	return 0;
}

/*
 * Function is used to change the pcm hardware parameters.
 */
static int usbmic_pcmcap_hwparams(struct snd_pcm_substream *substream,
				  struct snd_pcm_hw_params *hw_params)
{
	struct usbmic_device *device = substream->private_data;
	int rval;
	int buffer_bytes = params_buffer_bytes(hw_params);
	
	dev_info(getdev(device), "%s", __FUNCTION__);
	
	device->rate = params_rate(hw_params)/dbg_div;
		
	rval = snd_pcm_lib_alloc_vmalloc_buffer(substream, buffer_bytes);
	if (rval < 0) {
		dev_info(getdev(device), "Error %d while allocating"
			 "%dB buffer for stream", buffer_bytes, rval);
	}
	
	return rval;
}

/*
 * Function used to free the resources allocated by the hardware configuration.
 */
static int usbmic_pcmcap_hwfree(struct snd_pcm_substream *substream)
{
	struct usbmic_device *device = substream->private_data;
	
	dev_info(getdev(device), "%s", __FUNCTION__);
	
	/* wait until all urbs will be handled */
	usb_wait_anchor_empty_timeout(&device->usb_anchor, -1);
	/*usb_kill_anchored_urbs(&device->usb_anchor);*/
	
	snd_pcm_lib_free_vmalloc_buffer(substream);				
	
	return 0;
}

/*
 * Function is always called when the pcm is ready.
 */
static int usbmic_pcmcap_prepare(struct snd_pcm_substream *substream)
{
	struct usbmic_device *device = substream->private_data;
	int err;
	
	dev_info(getdev(device), "%s", __FUNCTION__);
		
	/* set the buffer position to it's beginning */
	atomic_set(&device->buffer_pos, 0);
	device->period_pos = 0;
	
	/*usb_unpoison_anchored_urbs(&device->usb_anchor);*/
	
	err = usbmic_submit_urbs(device);
	if (err < 0)
		return err;
	
	err = usbmic_data_stop(device, 1);
	if (err < 0)
		return err;	
		
	err = usbmic_set_freq(device, device->rate, 1);
	if (err < 0)
		return err;
	
	return 0;
}

/*
 * Function is called always when the pcm is started, stopped or paused.
 */
static int usbmic_pcmcap_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct usbmic_device *device = substream->private_data;
	
	dev_info(getdev(device), "%s", __FUNCTION__);
	
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START: /* the pcm is starting */
		dev_info(getdev(device), "trigger start");
		atomic_set(&device->running, 1);
		usbmic_data_start(device, 0);
		break;
	case SNDRV_PCM_TRIGGER_STOP: /* the pcm is stopped */
		dev_info(getdev(device), "trigger stop");
		usbmic_data_stop(device, 0);
		atomic_set(&device->running, 0);
		break;
	default:
		dev_info(getdev(device), "trigger unknown");	
		return -EINVAL;
	}
	return 0;	
}

/*
 * Function is called always when the PCM middle layer inquires the current
 * hardware position on the buffer.
 */
static inline snd_pcm_uframes_t usbmic_pcmcap_pointer(struct snd_pcm_substream 
						      *substream)
{
	struct usbmic_device *device = substream->private_data;
		
	dev_info(getdev(device), "%s", __FUNCTION__);	

	return bytes_to_frames(substream->runtime, atomic_read(&device->buffer_pos));
}

/*
 * Structure with operations that can be handled on the PCM.
 */
static struct snd_pcm_ops usbmic_pcmcap_ops = {
	.open		= usbmic_pcmcap_open,
	.close		= usbmic_pcmcap_close,
	.ioctl		= snd_pcm_lib_ioctl,
	.hw_params	= usbmic_pcmcap_hwparams,
	.hw_free	= usbmic_pcmcap_hwfree,
	.prepare	= usbmic_pcmcap_prepare,
	.trigger	= usbmic_pcmcap_trigger,
	.pointer	= usbmic_pcmcap_pointer,
	.page 		= snd_pcm_lib_get_vmalloc_page,
	.mmap 		= snd_pcm_lib_mmap_vmalloc,	
};

static void usbmic_card_free(struct snd_card *card)
{
	/* nothing to do */
}

/*
 * Function used to alloc urbs.
 */
static int usbmic_alloc_urbs(struct usbmic_device *device)
{
	int i = 0;
	char *urb_buf = NULL;
	int err = 0;
	
	/* For every urb */
	for (i = 0; i < ARRAY_SIZE(device->urbs); ++i) {
		/* Alloc the memory */
		device->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
		if (!device->urbs[i]) {
			err = -ENOMEM;
			goto error;
		}
		/* Alloc the memory for a buffer */
		urb_buf = kmalloc(URB_BUF_SIZE, GFP_KERNEL);
		if (!urb_buf) {
			err = -ENOMEM;
			goto error;
		}
		/* Configure urbs */
		usb_fill_bulk_urb(device->urbs[i], device->usbdev,
				  usb_rcvbulkpipe(device->usbdev,
						  device->usb_ep_in),
				  urb_buf, URB_BUF_SIZE,
				  usbmic_urbrecv_complete, device);
		device->urbs[i]->transfer_flags |= URB_FREE_BUFFER;
	}
	
	return 0;
	
error:
	usbmic_free_urbs(device);

	return err;
}

/*
 * Function used to check whether plugged in device is handled by this device.
 */
static int usbmic_probe(struct usb_interface *intf,
			const struct usb_device_id *uid)
{
	int i = 0;
	int rval = 0;
	char usb_path[32];
	unsigned int card_index;
	struct snd_card *card;
	struct usbmic_device *device;
	struct usb_host_interface *iface_desc;
	struct usb_endpoint_descriptor *endp_desc;
		
	dev_info(&intf->dev, "%s", __FUNCTION__);
	
	/* synchronize */
	mutex_lock(&probe_mutex);
	
	for (card_index = 0; card_index < SNDRV_CARDS; ++card_index)
		if (enable[card_index] && !(devices_used & (1 << card_index)))
			break;
	if (card_index >= SNDRV_CARDS)
		return -ENOENT;

	/* create the compatibile with ALSA sound card */	
	rval = snd_card_create(index[card_index], id[card_index], THIS_MODULE,
				sizeof(*device), &card);
	if (rval < 0) {
		dev_info(&intf->dev, "Create soundcard: error %d", rval);
		return rval;
	}

	/* initialize the structure */
	card->private_free = usbmic_card_free;	
	device = card->private_data;
	device->usbdev		= usb_get_dev(interface_to_usbdev(intf));
	device->usbintf		= intf;
	device->sndcard		= card;
	device->sndcard_idx	= card_index;
	init_usb_anchor(&device->usb_anchor);
	spin_lock_init(&device->lock);	
	tasklet_init(&device->tasklet, usbmic_urbrecv_complete_bh,
		     (unsigned long)device);	
	
	/* find device endpoints */
	iface_desc = intf->cur_altsetting;
	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
		endp_desc = &iface_desc->endpoint[i].desc;
		
		if (usb_endpoint_is_bulk_in(endp_desc))
			device->usb_ep_in = endp_desc->bEndpointAddress;
		else if (usb_endpoint_is_bulk_out(endp_desc))
			device->usb_ep_out = endp_desc->bEndpointAddress;
	}
	
	if (!(device->usb_ep_in && device->usb_ep_out)) {
		/* Probably bad usb configuration */
		rval = -ENODEV;
		goto probe_error;
	}		
	/* connect the sound card with the device */
	snd_card_set_dev(card, &intf->dev);
	
	usb_make_path(device->usbdev, usb_path, sizeof(usb_path));	
	strcpy(card->driver, CARD_NAME);
	snprintf(card->shortname,sizeof(card->shortname), "%s card", CARD_NAME);
	snprintf(card->longname, sizeof(card->longname),
		 "%s usb sound card at %s", CARD_NAME, usb_path);

	/* create pcm */	 
	rval = snd_pcm_new(card, CARD_NAME, 0, 0, 1, &device->sndpcm);
	if (rval < 0) {
		dev_info(&intf->dev, "Create PCM device: Error %d", rval);		
		goto probe_error;
	}
	/* set the device structure as a private_data in order to easily access it */
	device->sndpcm->private_data = device;
	strcpy(device->sndpcm->name, "usbmic");
	/* set pcm operations */
	snd_pcm_set_ops(device->sndpcm, SNDRV_PCM_STREAM_CAPTURE, 
			&usbmic_pcmcap_ops);	
	/* set also the device structure as the private data of usb interface */	 		 
	usb_set_intfdata(intf, device);
	
	/* Register urbs */	
	rval = usbmic_alloc_urbs(device);
	if (rval < 0) {
		dev_info(&intf->dev, "Alloc urbs : Error %d", rval);
		goto probe_error;
	}
	/* Register the created soundcard. */	
	rval = snd_card_register(card);
	if (rval < 0) {
		dev_info(&intf->dev, "Register card: Error %d", rval);
		goto probe_error;
	}
	
	devices_used |= 1 << card_index;

	mutex_unlock(&probe_mutex);
	
	dev_info(&intf->dev, "Probe ok");
	
	return 0;
	
probe_error:	
	dev_info(&intf->dev, "Probe error %d", rval);
	
	usbmic_free_urbs(device);
	usb_set_intfdata(intf, NULL);
	snd_card_free(card);	
	mutex_unlock(&probe_mutex);
	
	return rval;
}

/*
 * Function invoked when the device is plugged out.
 */
static void usbmic_disconnect(struct usb_interface *intf)
{	
	struct usbmic_device *device = usb_get_intfdata(intf);

	/* disconnect the soundcard */	
	snd_card_disconnect(device->sndcard);
	
	/* if the device is still in the CAPTURE mode stop the pcm */	
	if(atomic_read(&device->running))
		snd_pcm_stop(device->substream, SNDRV_PCM_STATE_XRUN);
	
	spin_lock(&waitqueue.lock);
	device->waiting = 1;
	wake_up_locked(&waitqueue);
	spin_unlock(&waitqueue.lock);
	
	/* poison anchored urbs */ 
	if (device->urbs[0])		
		usb_poison_anchored_urbs(&device->usb_anchor);
		
	/* and free then */
	usbmic_free_urbs(device);
		
	/* free also the interface private data */
	usb_set_intfdata(intf, NULL);	
	
	devices_used &= ~(1 << device->sndcard_idx);
	snd_card_free_when_closed(device->sndcard);	
			
	usb_put_dev(device->usbdev);
}

/* Table containing information which devices might be handled by this driver */
static const struct usb_device_id usbmic_table[] = {
	{ USB_DEVICE(USBMIC_VENDOR_ID, USBMIC_PRODUCT_ID) },
	{ }
};
MODULE_DEVICE_TABLE(usb, usbmic_table);

/* Structure used to describe the usb device driver */
static struct usb_driver usbmic_driver = {
	.name		= CARD_NAME,
	.probe		= usbmic_probe,
	.disconnect	= usbmic_disconnect,
	.id_table	= usbmic_table,
};

/*
 * Function invoked when the module is being loaded.
 */
static int __init usbmic_init(void)
{
	int result;
	
	result = usb_register(&usbmic_driver);
	if (result)
		err("usb_register failed. Error number %d", result);
	
	return result;
}

/*
 * Function invoked when the module is being unloaded.
 */
static void __exit usbmic_exit(void)
{
	usb_deregister(&usbmic_driver);
}

module_init(usbmic_init);
module_exit(usbmic_exit);
